package com.dfiles.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.nio.channels.FileChannel;
import java.util.List;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.drawable.Drawable;
import android.media.ThumbnailUtils;
import android.net.Uri;
import android.util.Log;

import com.dfiles.bean.DFile;
import com.dfiles.provider.FileTypeHelper.FileTypeAll;

/**
 * 文件操作类
 * 
 * @author damon.han
 * 
 */
public class FileUtils {
	private static int INSTALLED = 0; // 表示已经安装，且跟现在这个apk文件是一个版本
	private static int UNINSTALLED = 1; // 表示未安装
	private static int INSTALLED_UPDATE = 2; // 表示已经安装，版本比现在这个版本要低

	/**
	 * 检查文件后缀名
	 * 
	 * @param checkItsEnd
	 * @param fileEndings
	 * @return
	 */
	public static boolean checkEndsWithInStringArray(String checkItsEnd, String[] fileEndings) {
		if (checkItsEnd == null || fileEndings == null) {
			return false;
		}
		if (checkItsEnd.lastIndexOf(".") == -1) {
			return false;
		}
		String end = checkItsEnd.substring(checkItsEnd.lastIndexOf("."), checkItsEnd.length());
		for (String aEnd : fileEndings) {
			if (end.equalsIgnoreCase(aEnd))
				return true;
		}
		return false;
	}

	/** 获得文件大小表示 */
	public static String formatFileSize(long len) {
		if (len < 1024) {
			return len + " B";
		} else if (len < 1024 * 1024) {
			return len / 1024 + "." + (len % 1024 / 10 % 100) + " KB";
		} else if (len < 1024 * 1024 * 1024) {
			return len / (1024 * 1024) + "." + len % (1024 * 1024) / 10 % 100 + " MB";
		} else {
			return len / (1024 * 1024 * 1024) + "." + len % (1024 * 1024 * 1024) / 10 % 100 + " G";
		}
	}

	/**
	 * 根据路径获得文件名
	 * 
	 * @param path
	 * @return
	 */
	public static String getFileName(String path) {
		if (path == null || path.equals("") || !path.contains(File.separator)) {
			return "";
		}
		return path.substring(path.lastIndexOf(File.separator) + 1, path.length());
	}

	/**
	 * 缩放图片
	 * 
	 * @param b
	 * @param newWidth
	 * @param newHeight
	 * @return
	 */
	public static Bitmap zoomImage(Bitmap b, int newWidth, int newHeight) {
		int width = b.getWidth();
		int height = b.getHeight();
		float scaleWidth = ((float) newWidth) / width;
		float scaleHeight = ((float) newHeight) / height;
		// 取得想要缩放的matrix
		Matrix matrix = new Matrix();
		matrix.setScale(scaleWidth, scaleHeight);
		// 获得新图片
		Bitmap newB = Bitmap.createBitmap(b, 0, 0, width, height, matrix, true);
		return newB;
	}

	// 获取文件头信息
	public static String getFileHeader(String filePath) {
		FileInputStream is = null;
		String value = null;
		try {
			is = new FileInputStream(filePath);
			byte[] b = new byte[3];
			is.read(b, 0, b.length);
			value = bytesToHexString(b);
		} catch (Exception e) {
		} finally {
			if (null != is) {
				try {
					is.close();
				} catch (IOException e) {
				}
			}
		}
		return value;
	}

	/**
	 * 获得文件内容的mime十六进制内容
	 * 
	 * @param src
	 * @return
	 */
	private static String bytesToHexString(byte[] src) {
		StringBuilder builder = new StringBuilder();
		if (src == null || src.length <= 0) {
			return null;
		}
		String hv;
		for (int i = 0; i < src.length; i++) {
			hv = Integer.toHexString(src[i] & 0xFF).toUpperCase();
			if (hv.length() < 2) {
				builder.append(0);
			}
			builder.append(hv);
		}
		return builder.toString();
	}

	/**
	 * 根据文件的后缀名获得文件类型
	 * 
	 * @param filePath
	 * @return 文件类型码
	 * 
	 */
	@Deprecated
	public static int getFileTypeBySuffix(String filePath, Context context) {
		int type = 0;
		// int type = Config.FILE_TYPE_NULL;
		// if (FileUtils.checkEndsWithInStringArray(filePath,
		// context.getResources().getStringArray(R.array.fileEndingImage))) {
		// type = Config.FILE_TYPE_IMAGE;
		// } else if (FileUtils.checkEndsWithInStringArray(filePath,
		// context.getResources().getStringArray(R.array.fileEndingAudio))) {
		// type = Config.FILE_TYPE_AUDIO;
		// } else if (FileUtils.checkEndsWithInStringArray(filePath,
		// context.getResources().getStringArray(R.array.fileEndingVideo))) {
		// type = Config.FILE_TYPE_VIDEO;
		// } else if (FileUtils.checkEndsWithInStringArray(filePath,
		// context.getResources().getStringArray(R.array.fileEndingPPT))) {
		// type = Config.FILE_TYPE_PPT;
		// } else if (FileUtils.checkEndsWithInStringArray(filePath,
		// context.getResources().getStringArray(R.array.fileEndingWord))) {
		// type = Config.FILE_TYPE_WORD;
		// } else if (FileUtils.checkEndsWithInStringArray(filePath,
		// context.getResources().getStringArray(R.array.fileEndingExcel))) {
		// type = Config.FILE_TYPE_EXCEL;
		// } else if (FileUtils.checkEndsWithInStringArray(filePath,
		// context.getResources().getStringArray(R.array.fileEndingApk))) {
		// type = Config.FILE_TYPE_APK;
		// } else if (FileUtils.checkEndsWithInStringArray(filePath,
		// context.getResources().getStringArray(R.array.fileEndingPdf))) {
		// type = Config.FILE_TYPE_PDF;
		// } else if (FileUtils.checkEndsWithInStringArray(filePath,
		// context.getResources().getStringArray(R.array.fileEndingWebText))) {
		// type = Config.FILE_TYPE_WEB;
		// }
		return type;
	}

	public static int[] getImageWidthAndHeight(String imagePath) {
		int[] result = new int[2];
		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		// 获取图片的宽和高，这里的bitmap并没有加载到内存为null
		int w = options.outWidth;
		int h = options.outHeight;
		result[0] = w;
		result[1] = h;
		return result;
	}

	/**
	 * @param path
	 *            -原始路径
	 * @param desWidth
	 *            --目标宽度
	 * @param desHeight
	 *            --目标高度
	 * @return
	 */
	public static Bitmap getImageThumbnail(String path, int desWidth, int desHeight) {
		BitmapFactory.Options opts = new BitmapFactory.Options();
		opts.inJustDecodeBounds = true;// 设置成了true,不占用内存，只获取bitmap宽高
		BitmapFactory.decodeFile(path, opts);
		int minSize = desWidth < desHeight ? desWidth : desHeight;
		opts.inSampleSize = computeSampleSize(opts, minSize, 2048 * 1280);
		opts.inJustDecodeBounds = false;// 这里一定要将其设置回false，因为之前我们将其设置成了true
		opts.inPurgeable = true;
		opts.inInputShareable = true;
		opts.inDither = false;
		opts.inPurgeable = true;
		opts.inTempStorage = new byte[16 * 1024];
		opts.inPreferredConfig = Bitmap.Config.RGB_565;// 低颜色数
		FileInputStream is = null;
		Bitmap bmp = null;
		try {
			is = new FileInputStream(path);
			bmp = BitmapFactory.decodeFileDescriptor(is.getFD(), null, opts);
			double scale = getScaling(opts.outWidth * opts.outHeight, desWidth * desHeight);
			Bitmap bmp2 = Bitmap.createScaledBitmap(bmp, (int) (opts.outWidth * scale), (int) (opts.outHeight * scale), true);
			// ByteArrayOutputStream bos = new ByteArrayOutputStream();
			// 试验生成图片的大小
			// FileOutputStream baos = new FileOutputStream(new
			// File(Config.DATA_PATH + "/aaa.png"));
			// bmp2.compress(Bitmap.CompressFormat.JPEG, 100, baos);
			// // bmp2.recycle();
			// bmp.recycle();
			return bmp2;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (is != null) {
					is.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			// System.gc();
		}
		return null;
		// 单纯使用工具类会大小不合适
		// Bitmap b =
		// ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(path),
		// desWidth, desHeight, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
		// FileOutputStream baos= null;
		// try {
		// baos = new FileOutputStream(new File(Config.DATA_PATH +
		// "/aaa.png"));
		// } catch (FileNotFoundException e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// }
		// b.compress(Bitmap.CompressFormat.JPEG, 100, baos);
		// return b;
	}

	/**
	 * 获取视频的缩略图 先通过ThumbnailUtils来创建一个视频的缩略图，然后再利用ThumbnailUtils来生成指定大小的缩略图。
	 * 如果想要的缩略图的宽和高都小于MICRO_KIND，则类型要使用MICRO_KIND作为kind的值，这样会节省内存。
	 * 
	 * @param videoPath
	 *            视频的路径
	 * @param width
	 *            指定输出视频缩略图的宽度
	 * @param height
	 *            指定输出视频缩略图的高度度
	 * @param kind
	 *            参照MediaStore.Images.Thumbnails类中的常量MINI_KIND和MICRO_KIND。
	 *            其中，MINI_KIND: 512 x 384，MICRO_KIND: 96 x 96
	 * @return 指定大小的视频缩略图
	 */
	public static Bitmap getVideoThumbnail(String videoPath, int width, int height, int kind) {
		Bitmap bitmap = null;
		// 获取视频的缩略图
		bitmap = ThumbnailUtils.createVideoThumbnail(videoPath, kind);
		// bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height,
		// ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
		return bitmap;
	}

	/**
	 * compute Sample Size
	 * 
	 * @param options
	 * @param minSideLength
	 * @param maxNumOfPixels
	 * @return
	 */
	public static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
		int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels);

		int roundedSize;
		if (initialSize <= 8) {
			roundedSize = 1;
			while (roundedSize < initialSize) {
				roundedSize <<= 1;
			}
		} else {
			roundedSize = (initialSize + 7) / 8 * 8;
		}

		return roundedSize;
	}

	/**
	 * compute Initial Sample Size
	 * 
	 * @param options
	 * @param minSideLength
	 * @param maxNumOfPixels
	 * @return
	 */
	private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
		double w = options.outWidth;
		double h = options.outHeight;
		int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
		int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength));
		if (upperBound < lowerBound) {
			// return the larger one when there is no overlapping zone.
			return lowerBound;
		}
		if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
			return 1;
		} else if (minSideLength == -1) {
			return lowerBound;
		} else {
			return upperBound;
		}
	}

	// 图标的主题-黑色或者白色
	public static final int IMAGE_THEME_BLACK = 0;
	public static final int IMAGE_THEME_WHITE = 1;

	/**
	 * 复制文件
	 * 
	 * @param input
	 *            -输入流
	 * @param target
	 */
	public static void copyFile(InputStream input, String targetPath) {
		if (input == null || targetPath == null || targetPath.equals("")) {
			return;
		}
		BufferedOutputStream bos = null;
		try {
			bos = new BufferedOutputStream(new FileOutputStream(targetPath));
			byte[] b = new byte[1024 * 5];
			int length;
			while ((length = input.read(b)) != -1) {
				bos.write(b, 0, length);
			}
			bos.flush();
		} catch (Exception e) {
			return;
		} finally {
			if (input != null) {
				try {
					input.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (bos != null) {
				try {
					bos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 复制文件
	 * 
	 * @param resource
	 *            -源文件
	 * @param target
	 *            -目标文件
	 */
	public static void copyFile(File source, File target) {
		if (source == null) {
			return;
		}
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;
		try {
			bis = new BufferedInputStream(new FileInputStream(source));
			bos = new BufferedOutputStream(new FileOutputStream(target));
			byte[] b = new byte[1024 * 5];
			int length;
			while ((length = bis.read(b)) != -1) {
				bos.write(b, 0, length);
			}
			bos.flush();
		} catch (Exception e) {
			return;
		} finally {
			if (bis != null) {
				try {
					bis.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if (bos != null) {
				try {
					bos.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

	/*
	 * 复制文件夹包含其中的文件
	 */
	public static void copyDir(String sourceDir, String targetDir) {
		if (targetDir == null) {
			return;
		}
		File t = new File(targetDir);
		if (!t.canWrite()) {
			return;
		}
		t.mkdirs();

		File[] file = (new File(sourceDir)).listFiles();
		for (int i = 0; i < file.length; i++) {
			if (file[i].isFile()) {
				File sourceFile = file[i];
				File targetFile = new File(new File(targetDir).getAbsolutePath() + File.separator + file[i].getName());
				copyFile(sourceFile, targetFile);
			} else if (file[i].isDirectory()) {
				String dir1 = sourceDir + File.separator + file[i].getName();
				String dir2 = targetDir + File.separator + file[i].getName();
				copyDir(dir1, dir2);
			}
		}
	}

	/**
	 * 删除目标文件或者文件夹
	 * 
	 * @param filePath
	 */
	public static void del(String filePath) {
		File f = new File(filePath);
		if (!f.canWrite()) {
			return;
		}
		if (f.exists() && f.isDirectory()) {

			if (f.listFiles().length == 0) {// 若目录下没有文件则直接删除
				f.delete();

			} else {

				File delFile[] = f.listFiles();
				int i = f.listFiles().length;
				for (int j = 0; j < i; j++) {
					if (delFile[j].isDirectory()) {
						del(delFile[j].getAbsolutePath());
					}
					delFile[j].delete();
				}
			}
		} else if (f.exists() && f.isFile()) {
			f.delete();
		}
	}

	/**
	 * 获得缩放比例-(用于图片缩放)
	 * 
	 * @param src
	 * @param des
	 * @return
	 */
	private static double getScaling(int src, int des) {
		/**
		 * 目标尺寸÷原尺寸 sqrt开方，得出宽高百分比
		 */
		double scale = Math.sqrt((double) des / (double) src);
		return scale;
	}

	/**
	 * @param context
	 * @param filePath
	 * @param type
	 */
	public static void previewFile(Context context, DFile ef) {
		if (ef == null) {
			UIHelper.makeToast(context, "预览失败");
			return;
		}
		if (isMine(context, ef.packageName)) {
			return;
		}
		FileTypeAll type = ef.type;
		Intent intent = null;
		File file = null;
		if (ef.path != null) {
			file = new File(ef.path);
			if (!file.exists()) {
				UIHelper.makeToast(context, "预览失败");
				return;
			}
		}
		try {
			switch (type) {
				case FILE_TYPE_OTHER :
					break;
				case FILE_TYPE_IMAGE :
					// 点击图片全屏查看原图
					intent = IntentUtils.getImageFileIntent(file);
					break;
				case FILE_TYPE_AUDIO :// 音频
					intent = IntentUtils.getAudioFileIntent(file);
					break;
				case FILE_TYPE_VIDEO :// 视频
					intent = IntentUtils.getVideoFileIntent(file);
					break;
				case FILE_TYPE_PPT :// ppt
					intent = IntentUtils.getPPTFileIntent(file);
					break;
				case FILE_TYPE_WORD :// word
					intent = IntentUtils.getWordFileIntent(file);
					break;
				case FILE_TYPE_EXCEL :// excel
					intent = IntentUtils.getExcelFileIntent(file);
					break;
				case FILE_TYPE_TEXT :// txt
					intent = IntentUtils.getTextFileIntent(file);
					break;
				case FILE_TYPE_APK :// apk文件
					PackageManager pm = context.getPackageManager();
					PackageInfo packageInfo = pm.getPackageArchiveInfo(file.getPath(), PackageManager.GET_ACTIVITIES);
					ActivityInfo ai = packageInfo.activities[0];
					/** 得到包名 */
					String packageName = packageInfo.packageName;
					if (isMine(context, packageName)) {
						UIHelper.makeToast(context, "请不要打开自身");
						return;
					}
					/** apk的版本号码 int */
					int versionCode = packageInfo.versionCode;
					/** 安装处理类型 */
					int apkState = getAPKState(pm, packageName, versionCode);
					if (apkState == 0) {// 已经安装且版本相同
						intent = pm.getLaunchIntentForPackage(packageName);// 根据包名启动
					} else {
						intent = IntentUtils.getApkFileIntent(file);// 打开apk文件进行安装
					}
					break;
				case FILE_TYPE_APP :// 应用程序
					ComponentName cn = new ComponentName(ef.packageName, ef.activityName);
					intent = IntentUtils.getApkFileIntent(cn);// 打开一个应用程序
					break;
				case FILE_TYPE_PDF :// PDF
					intent = IntentUtils.getPdfFileIntent(file);// 打开一个pdf文件
					break;
				case FILE_TYPE_WEB :// html等
					intent = IntentUtils.getHtmlFileIntent(ef.path);// 打开一个html文件
					break;
				default :
					intent = IntentUtils.getTextFileIntent(file);
					break;
			}
			if (null != intent) {

				context.startActivity(intent);
			}
		} catch (Exception e) {
			e.printStackTrace();
			Log.e(FileUtils.class.getName(), "调用activity出错");
			UIHelper.makeToast(context, "预览失败");
		}
	}

	/**
	 * 判断是否自身
	 * 
	 * @param packageName
	 * @return
	 */
	public static boolean isMine(Context context, String packageName) {
		if (packageName == null) {
			return false;
		}
		if (packageName.contains("com.ebt.app")) {
			return true;
		}
		return false;
	}

	/**
	 * 获取应用程序的图标
	 * 
	 * @param context
	 * @param packageName
	 *            -包名
	 * @param className
	 *            -类名
	 * @return
	 */
	public static Drawable getAppIcon(Context context, String packageName, String className) {
		Drawable icon = null;
		PackageManager pkgMgr = context.getPackageManager();
		try {
			ComponentName cn = new ComponentName(packageName, className);
			icon = pkgMgr.getActivityIcon(cn);
		} catch (Exception e) {
			Log.w("getAppIcon", packageName + "获取应用程序图标异常");
			e.printStackTrace();
		}
		return icon;
	}

	/**
	 * @param context
	 * @param path
	 *            -apk文件绝对路径
	 * @return
	 */
	public static Drawable getApkIcon(Context context, String path) {
		Drawable icon = null;
		PackageManager pm = context.getPackageManager();
		PackageInfo packageInfo = pm.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES);
		try {
			if (packageInfo != null) {
				ApplicationInfo appInfo = packageInfo.applicationInfo;
				if (appInfo != null) {
					appInfo.sourceDir = path;
					appInfo.publicSourceDir = path;
					icon = appInfo.loadIcon(pm);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return icon;
	}

	/**
	 * 
	 * @Description: 复制文件
	 * @param
	 * @return void
	 * @throws
	 */
	public static void transferCopy(File source, File target) {
		FileChannel in = null;
		FileChannel out = null;
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try {
			fis = new FileInputStream(source);
			fos = new FileOutputStream(target);
			in = fis.getChannel();
			out = fos.getChannel();
			in.transferTo(0, in.size(), out);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 
	 * @param context
	 * @param packageName
	 * @param versionCode
	 * @return int
	 * @throws
	 */
	public static int getAPKState(PackageManager pm, String packageName, int versionCode) {
		List<PackageInfo> list = pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
		for (PackageInfo info : list) {
			String pName = info.packageName;
			int pVersionCode = info.versionCode;
			if (packageName.endsWith(pName)) {
				// 如果这个包名在系统已经安装过的应用中存在
				// Log.i("test","此应用安装过了");
				if (versionCode == pVersionCode) {
					// Log.i("test", "已经安装，不用更新，可以卸载该应用");
					return INSTALLED;
				} else if (versionCode > pVersionCode) {
					// Log.i("test", "已经安装，有更新");
					return INSTALLED_UPDATE;
				}
			}
		}
		Log.i("test", "未安装该应用，可以安装");
		return UNINSTALLED;
	}

	/**
	 * 获取调用系统自带文件管理器选中的文件的路径
	 * 
	 * @param context
	 * @param uri
	 * @return
	 */
	public static String getPath(Context context, Uri uri) {
		if ("content".equalsIgnoreCase(uri.getScheme())) {
			String[] projection = {"_data"};
			Cursor cursor = null;
			try {
				cursor = context.getContentResolver().query(uri, projection, null, null, null);
				int column_index = cursor.getColumnIndexOrThrow("_data");
				if (cursor.moveToFirst()) {
					return cursor.getString(column_index);
				}
			} catch (Exception e) {
			}
		} else if ("file".equalsIgnoreCase(uri.getScheme())) {
			return uri.getPath();
		}
		return null;
	}

	public static String getMimeType(String fileName) {
		FileNameMap fileNameMap = URLConnection.getFileNameMap();
		String type = fileNameMap.getContentTypeFor(fileName);
		return type;
	}
}
